package templates

import (
	"libvirt.org/go/libvirtxml"
)

func (b *Builder) buildControllers(tmpl *DomainTemplate) []libvirtxml.DomainController {
	controllers := []libvirtxml.DomainController{}

	switch tmpl.Architecture {
	case ArchX86_64:
		// USB controller (common)
		controllers = append(controllers, libvirtxml.DomainController{
			Type:  "usb",
			Index: func(i uint) *uint { return &i }(0),
			Model: "qemu-xhci",
			// Ports: func(p uint) *uint { return &p }(15), // Ports field not available in current libvirtxml
		})

		// PCIe root
		controllers = append(controllers, libvirtxml.DomainController{
			Type:  "pci",
			Index: func(i uint) *uint { return &i }(0),
			Model: "pcie-root",
		})

		// Add multiple PCIe root ports (14 ports for expansion)
		for i := uint(1); i <= 14; i++ {
			controllers = append(controllers, libvirtxml.DomainController{
				Type:  "pci",
				Index: func(idx uint) *uint { return &idx }(i),
				Model: "pcie-root-port",
			})
		}

		// SATA controller (x86_64 specific)
		controllers = append(controllers, libvirtxml.DomainController{
			Type:  "sata",
			Index: func(i uint) *uint { return &i }(0),
		})

		// Virtio-serial controller (common)
		controllers = append(controllers, libvirtxml.DomainController{
			Type:  "virtio-serial",
			Index: func(i uint) *uint { return &i }(0),
		})
	case ArchAARCH64:
		// USB controller (common)
		controllers = append(controllers, libvirtxml.DomainController{
			Type:  "usb",
			Index: func(i uint) *uint { return &i }(0),
			Model: "qemu-xhci",
		})

		// PCIe for ARM64 (virt machine)
		controllers = append(controllers, libvirtxml.DomainController{
			Type:  "pci",
			Index: func(i uint) *uint { return &i }(0),
			Model: "pcie-root",
		})

		// Virtio-serial (common)
		controllers = append(controllers, libvirtxml.DomainController{
			Type:  "virtio-serial",
			Index: func(i uint) *uint { return &i }(0),
		})
	default:
		// This should not happen if validation is working correctly,
		// but we include it for completeness and future-proofing
		return controllers
	}

	return controllers
}

func (b *Builder) buildNetworkInterface(tmpl *DomainTemplate) libvirtxml.DomainInterface {
	netInterface := libvirtxml.DomainInterface{
		Model: &libvirtxml.DomainInterfaceModel{
			Type: "virtio",
		},
	}

	// Configure network source
	networkName := tmpl.NetworkName
	if networkName == "" {
		networkName = "default"
	}

	switch tmpl.NetworkMode {
	case "bridge":
		netInterface.Source = &libvirtxml.DomainInterfaceSource{
			Bridge: &libvirtxml.DomainInterfaceSourceBridge{
				Bridge: networkName,
			},
		}
	case "user":
		netInterface.Source = &libvirtxml.DomainInterfaceSource{
			User: &libvirtxml.DomainInterfaceSourceUser{},
		}
	default: // "network" or empty
		netInterface.Source = &libvirtxml.DomainInterfaceSource{
			Network: &libvirtxml.DomainInterfaceSourceNetwork{
				Network: networkName,
			},
		}
	}

	return netInterface
}

// buildChannels builds the channel devices for the domain
func (b *Builder) buildChannels(tmpl *DomainTemplate) []libvirtxml.DomainChannel {
	channels := []libvirtxml.DomainChannel{
		{
			Target: &libvirtxml.DomainChannelTarget{
				VirtIO: &libvirtxml.DomainChannelTargetVirtIO{
					Name: "com.redhat.spice.0",
				},
			},
		},
		{
			Target: &libvirtxml.DomainChannelTarget{
				VirtIO: &libvirtxml.DomainChannelTargetVirtIO{
					Name: "org.libguestfs.channel.0",
				},
			},
		},
		{
			Target: &libvirtxml.DomainChannelTarget{
				VirtIO: &libvirtxml.DomainChannelTargetVirtIO{
					Name: "org.qemu.guest_agent.0",
				},
			},
		},
		{
			Target: &libvirtxml.DomainChannelTarget{
				VirtIO: &libvirtxml.DomainChannelTargetVirtIO{
					Name: "org.spice-space.webdav.0",
				},
			},
		},
	}
	return channels
}

func (b *Builder) buildInputs(tmpl *DomainTemplate) []libvirtxml.DomainInput {
	// Configure input devices based on architecture
	inputs := []libvirtxml.DomainInput{}

	// Add tablet for better mouse integration (common across architectures)
	inputs = append(inputs, libvirtxml.DomainInput{
		Type: "tablet",
		Bus:  "usb",
	})

	inputs = append(inputs, libvirtxml.DomainInput{
		Type: "mouse",
		Bus:  "ps2",
	})
	inputs = append(inputs, libvirtxml.DomainInput{
		Type: "keyboard",
		Bus:  "ps2",
	})

	return inputs
}

func (b *Builder) buildGraphics(tmpl *DomainTemplate) []libvirtxml.DomainGraphic {
	return []libvirtxml.DomainGraphic{
		{
			Spice: &libvirtxml.DomainGraphicSpice{
				AutoPort: "yes",
			},
		},
		{
			VNC: &libvirtxml.DomainGraphicVNC{
				AutoPort: "yes",
			},
		},
	}
}

// BuildDefaultTemplate creates a default template with sensible defaults
func BuildDefaultTemplate(name, diskPath string) *DomainTemplate {
	return &DomainTemplate{
		Name:         name,
		Memory:       4096, // 4 GiB
		VCPUs:        2,
		Architecture: ArchX86_64,
		BootMode:     BootModeBIOS,
		DiskPath:     diskPath,
		DiskSize:     20, // 20 GiB
		DiskBus:      "virtio",
		NetworkMode:  "network",
		NetworkName:  "default",
		OSVariant:    "",
		EnableUEFI:   false,
		SecureBoot:   false,

		// CDROM defaults
		CDROMPath: "",
		CDROMBus:  "",
		CDROMBoot: false,
	}
}

// BuildUEFIX86Template creates a UEFI x86_64 template
func BuildUEFIX86Template(name, diskPath string) *DomainTemplate {
	tmpl := BuildDefaultTemplate(name, diskPath)
	tmpl.BootMode = BootModeUEFI
	tmpl.EnableUEFI = true
	return tmpl
}

// BuildUEFIARM64Template creates a UEFI ARM64 template
func BuildUEFIARM64Template(name, diskPath string) *DomainTemplate {
	tmpl := BuildDefaultTemplate(name, diskPath)
	tmpl.Architecture = ArchAARCH64
	tmpl.BootMode = BootModeUEFI
	tmpl.EnableUEFI = true
	return tmpl
}

// BuildCDROMTemplate creates a template with CDROM support
func BuildCDROMTemplate(name, diskPath, cdromPath string) *DomainTemplate {
	tmpl := BuildDefaultTemplate(name, diskPath)
	tmpl.CDROMPath = cdromPath
	tmpl.CDROMBus = "ide"
	tmpl.CDROMBoot = true
	return tmpl
}
